package com.keya.features.dicom;

import cn.hutool.core.util.ObjectUtil;
import com.keya.dicomtask.DcmInfoBO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.dcm4che3.data.Attributes;
import org.dcm4che3.data.Tag;
import org.dcm4che3.data.VR;
import org.dcm4che3.io.DicomInputStream;
import org.dcm4che3.io.DicomOutputStream;
import org.dcm4che3.util.SafeClose;
import org.dcm4che3.util.TagUtils;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Dicom文件工具类.
 *
 * @author : xf.he
 * @version : 1.0 2023/8/7
 * @since : 1.0
 **/
@Slf4j
public class DicomFileUtils {

    private static final ImageReader imageReader = ImageIO.getImageReadersByFormatName("DICOM").next();

    // a generic method to replace or remove a tag value
    public static void desensitizeTag(Attributes dcmObj, int tag, VR vr, String replaceValue) {
        if (StringUtils.isNotEmpty(replaceValue)) {
            dcmObj.setString(tag, vr, replaceValue);
        }
    }

    public static boolean isDicom(File file) {
        if (FileUtils.sizeOf(file) == 0)
            return false;
        try {
            byte[] data = FileUtils.readFileToByteArray(file);
            if (data.length < 128) {
                return false;
            }
            int b0 = data[0] & 255, b1 = data[1] & 255, b2 = data[2] & 255, b3 = data[3] & 255;
            if (data[128] == 68 && data[129] == 73 && data[130] == 67 && data[131] == 77)
                return true;
            else return (b0 == 8 || b0 == 2) && b1 == 0 && b3 == 0;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }


    public static boolean dicom2JPEG(File srcDicomFile, File destJPEGFile) throws IOException {
        Iterator<ImageReader> iter = ImageIO.getImageReadersByFormatName("DICOM");
        ImageReader reader = iter.next();
        ImageInputStream iis = ImageIO.createImageInputStream(srcDicomFile);
        BufferedImage bi;
        try {
            reader.setInput(iis, false);
            bi = readImage(iis);
            if (bi == null) {
                return false;
            }
            ImageIO.write(bi, "jpg", destJPEGFile);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } finally {
            SafeClose.close(iis);
        }
    }

    private static final int frame = 1;

    private static BufferedImage readImage(ImageInputStream iis) throws IOException {
        imageReader.setInput(iis);
        return imageReader.read(frame - 1, readParam());
    }

    private static ImageReadParam readParam() {
        return imageReader.getDefaultReadParam();
    }


    public static DcmInfoBO getDcmInfoBO(File dcm) {
        if (!DicomFileUtils.isDicom(dcm)) {
            return null;
        }
        try (DicomInputStream dicomInputStream = new DicomInputStream(dcm)) {
            Attributes attributes = dicomInputStream.readDataset();
            String StudyInstanceUID = attributes.getString(Tag.StudyInstanceUID);
            String SeriesInstanceUID = attributes.getString(Tag.SeriesInstanceUID);
            String SOPInstanceUID = attributes.getString(Tag.SOPInstanceUID);
            String AccessionNumber = attributes.getString(Tag.AccessionNumber);
            if (StringUtils.isEmpty(AccessionNumber)) {
                AccessionNumber = "AccessionNumber";
            }
            DcmInfoBO dcmInfoBO = new DcmInfoBO();
            dcmInfoBO.setSeriesInstanceUID(SeriesInstanceUID);
            dcmInfoBO.setStudyInstanceUID(StudyInstanceUID);
            dcmInfoBO.setAccessionNumber(AccessionNumber);
            dcmInfoBO.setSOPInstanceUID(SOPInstanceUID);
            return dcmInfoBO;
        } catch (Exception e) {
            log.error("获取dicom信息错误" + dcm.getPath(), e);
        }
        return null;
    }


    // a method to create a hashmap of tag names and values from an Attributes object
    public static Map<String, String> createTagVRMap(Attributes dcmObj) throws Exception {
        Map<String, String> tagVRMap = new HashMap<>();
        dcmObj.accept((attrs, tag, vr, value) -> {
            String tagName = TagUtils.toString(tag);
            String tagValue = String.format("%d-%s-%s", tag, vr, value);
            tagVRMap.put(tagName, tagValue);
            return true;
        }, true);
        return tagVRMap;
    }

    public static void dicomDesensitize(String filePath, String targetPath, TagOptionInfo tagOptionInfo) {
        File srcFile = new File(filePath);
        if (!isDicom(srcFile)) {
            return;
        }
        File targetFile = new File(targetPath + "/" + srcFile.getName());
        try (DicomInputStream din = new DicomInputStream(srcFile);
             DicomOutputStream dos = new DicomOutputStream(targetFile)) {
            Attributes dcmObj = din.readDataset();
            for (String info : tagOptionInfo.getList()) {
                if (info.split("=").length != 2) {
                    continue;
                }
                String attr_name = info.split("=")[0].trim();
                String attr_value = info.split("=")[1].trim();
                int tag = TagUtils.forName(attr_name);
                if (ObjectUtil.isEmpty(tag)) {
                    continue;
                }
                VR vr = dcmObj.getVR(tag);
                if (ObjectUtil.isEmpty(vr)) {
                    vr = VR.SH;
                }
                desensitizeTag(dcmObj, tag, vr, attr_value);
            }
            din.close();
            Attributes fmi = din.readFileMetaInformation();
            dos.writeDataset(fmi, dcmObj);
            dos.finish();
            dos.flush();
        } catch (IOException e) {
            log.error("dicom desensitize error", e);
        }
    }


}
